Skip to main content

Notifications

One hook. One config.

The Config

Enable notifications with a single flag

config.json:

{
"WEBVIEW_CONFIG": {
"notifications": {
"enabled": true
}
}
}

The Hook

const { scheduleLocal, registerForPush, subscribeToTopic } = useNotification()

// Schedule local notification
scheduleLocal({
title: "Hey!",
body: "You got a message",
badge: 5,
})

scheduleLocal({
title: "New Friend Request",
body: "Sarah wants to be your friend",
data: {
type: "friend_request",
fromUserId: 456,
requestId: "req_789",
},
actions: [
{ title: "Accept", action: "accept" },
{ title: "Decline", action: "decline" },
],
})

// Register for push notifications
registerForPush()

// Subscribe to topics after registering for push
subscribeToTopic("news")

scheduleLocal Keys

Required Keys:

  • title (string) - notification title (default: "Notification")
  • body (string) - notification body text (default: "You have a new message")

Optional Keys:

  • channel (string) - channel ID: "default" | "urgent" (default: "default")
  • badge (number) - badge count on app icon
  • actions (array) - action buttons [{title, action}]
  • largeImage (string) - large image URL for notification body and BIG_IMAGE style
  • style (string) - "BASIC" | "BIG_TEXT" | "BIG_IMAGE" | "ACTION_BUTTONS" (default: "BASIC")
  • priority (number) - notification priority (default: 0)
  • vibrate (boolean) - enable vibration (default: true)
  • autoCancel (boolean) - auto dismiss on tap (default: true)
  • data (object) - extra data for notification endpoint

Notification Channels & Sound System

How sounds work now: Sounds are automatically configured per channel (required for Android 8.0+). You cannot set sounds per individual notification.

Two predefined channels with automatic sound configuration:

  • default (default channel)

    • Uses notification_sound_default.mp3 if available in public/
    • Fallback: System default notification sound
    • Importance: DEFAULT
  • urgent

    • Uses notification_sound_urgent.mp3 if available in public/
    • Fallback: System alarm sound
    • Importance: HIGH

Sound assets are completely optional - the system automatically falls back to appropriate system sounds if custom assets are not provided.

Notification Types

  • Local: Triggers locally
  • Push: Triggered by firebase

Styles

  • BASIC - title + text (default)
  • BIG_TEXT - wall of text that expands
  • BIG_IMAGE - shows picture
  • ACTION_BUTTONS - buttons

All notification clicks route to /notification

Notification tap:

<ip>/notification?data={"orderId":123,"status":"shipped"}

Action button tap:

<ip>/notification?action=track_order&data={"orderId":123,"status":"shipped"}

Your middleware handles everything:

app.get("/notification", (req, res) => {
const { action, data } = req.query
const payload = JSON.parse(data || "{}")

if (action === "track_order") {
res.redirect(`/tracking/${payload.orderId}`)
} else if (action === "view_details") {
res.redirect(`/order/${payload.orderId}`)
} else {
// Regular notification click
res.redirect(`/order/${payload.orderId}`)
}
})

Assets Logic

Images

Build-time processing (automatic - both platforms):

  • Place in public/notification-icon.png → Android: ic_notification, iOS: NotificationIcon
  • Place in public/notification-large.png → Android: ic_notification_large, iOS: NotificationLargeIcon
  • Android: Auto-copied to res/drawable/ during build
  • iOS: Auto-copied to Assets.xcassets/ during build
  • Accepted formats:
    • Android: png, jpg, jpeg, gif, bmp, svg, webp
    • iOS: png, jpg, jpeg, webp
  • Fallback chain for icon: notification-icon.png -> app icon
  • Fallback chain for large icon: notification url -> notification-large.png -> app icon

Runtime images:

scheduleLocal({
largeImage: "https://example.com/avatar.png", // optional large image URL
style: "BIG_IMAGE",
})

If fetching the image fails, normal icon and text are shown without the BIG_IMAGE style While the image is being loaded

Sounds

Build-time processing (automatic - both platforms):

  • Place in public/notification-sound-default.mp3 → becomes notification_sound_default
  • Place in public/notification-sound-urgent.mp3 → becomes notification_sound_urgent
  • Android: Auto-copied to res/raw/ during build
  • iOS: Auto-copied to app bundle during build
  • Accepted formats:
    • Android: mp3, wav, ogg
    • iOS: mp3, wav, m4a, caf (caf recommended for iOS)

How to use sounds:

// Default notification sound (system notification sound or custom asset)
scheduleLocal({
title: "New message",
body: "You have a new message",
// No channel specified = uses "default" channel automatically
})

// Same as above but explicit
scheduleLocal({
title: "New message",
body: "You have a new message",
channel: "default", // Uses notification_sound_default.mp3 if available, else system default
})

// Urgent notification sound (system alarm sound or custom asset)
scheduleLocal({
title: "Emergency Alert",
body: "Urgent attention required!",
channel: "urgent", // Uses notification_sound_urgent.mp3 if available, else system alarm
})

Push Notification Payload Format

Push notifications use exactly the same format as scheduleLocal(). Simply stringify the same object you would pass to scheduleLocal():

Example: Convert scheduleLocal to push:

// This object works with scheduleLocal
const notificationObj = {
title: "Order Update",
body: "Your order is ready!",
style: "BIG_TEXT",
channel: "urgent",
badge: 2,
data: {
orderId: "12345",
userId: "user123",
deepLink: "/orders/12345",
},
actions: [
{ action: "view", title: "View Order" },
{ action: "dismiss", title: "Dismiss" },
],
}

// For push, just stringify it
const pushPayload = {
to: "DEVICE_FCM_TOKEN",
data: {
payload: JSON.stringify(notificationObj),
},
}

Firebase Console Setup (Required for Push Notifications)

Step 1: Create Firebase Project

  1. Go to Firebase Console
  2. Click "Add project" or "Create project"
  3. Enter project name (same as defined in config.json)
  4. Accept terms and click "Create project"
  5. Wait for project creation to complete

Step 2: Add Android App

  1. In Firebase console, click Android icon to add Android app
  2. Enter your app's package name (same as defined in config.json)
  3. Click "Register app"
  4. Click "Download google-services.json" to download config file
  5. Place google-services.json in your project's root directory
  6. Click "Next" and finish the setup

Step 3: Add iOS App

  1. In Firebase console, click iOS+ icon to add iOS app
  2. Enter your app's bundle ID (same as defined in config.json)
  3. Click "Register app"
  4. Click "Download GoogleService-Info.plist" to download config file
  5. Place GoogleService-Info.plist in your project's root directory
  6. Click "Next" and finish the setup

Step 4: Enable Cloud Messaging

  1. In Firebase console, go to Project Settings
  2. Click "Cloud Messaging" tab
  3. Verify Cloud Messaging API is enabled (should be enabled by default)
  4. For iOS: Upload your APNs authentication key or certificate
    • Go to Apple Developer Portal
    • Create APNs authentication key
    • Download the .p8 key file
    • Upload key ID and team ID in Firebase console

Platform-Specific Requirements

iOS Requirements:

  • Physical device required (push notifications don't work in simulator)
  • Apple Developer account for APNs setup
  • APNs authentication key configured in Firebase console

Android Requirements:

  • Google Play Services installed on device
  • Android 4.4+ (API level 19+) recommended

Firebase Initialization & Features

  • Auto-Initialization: Firebase automatically initializes if config files are present
  • Token Management: Automatic FCM token refresh and recovery
  • Topic Subscription: Subscribe to topics with subscribeToTopic() returns boolean success
  • Fallback Behavior: Local notifications work without Firebase setup
  • Timeout Handling: 30-second timeout for FCM token retrieval with retry logic

Resources & Further Reading